﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DriveBeamEditor.Controls.BeamNG.VehiclePartConfig;
using JBeamLibrary.Tools;
using JBeamLibrary.VehicleParts.Elements;
using JBeamLibrary.VehicleParts.Enums;

namespace DriveBeamEditor.Controls.BeamNG.SectionControls
{
    public partial class EngineControl : VehiclePartControl
    {
        #region CTORs

        public EngineControl()
        {
            InitializeComponent();
        }

        #endregion

        #region Events

        #region Binding sources

        private void gearsBindingSource_AddingNew(object sender, AddingNewEventArgs e)
        {
            if (DesignMode || VehiclePart == null)
            {
                e.NewObject = new Gear();
                return;
            }

            /* Avoid loop */
            if (e.NewObject is Gear) return;

            /* Not gear position left, do not allow */
            if (VehiclePart.Engine.Gears.Count >= Enum.GetValues(typeof(GearPosition)).Length)
            {
                MessageBox.Show(this,
                    @"The selected vehicle part's engine already contains the maximum amount of gears allowed.",
                    @"Gearbox full", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                gearsBindingSource.CancelEdit();
                gridGears.NotifyCurrentCellDirty(true);
                gridGears.CancelEdit();
                gridGears.NotifyCurrentCellDirty(false);
                return;
            }

            /* Create a new gear */
            e.NewObject = VehiclePart.Engine.Gears.GetNew();
        }

        private void gearsBindingSource_CurrentChanged(object sender, EventArgs e)
        {

        }

        private void engineTorqueBindingSource_AddingNew(object sender, AddingNewEventArgs e)
        {
            if (DesignMode || VehiclePart == null)
            {
                e.NewObject = new TorquePerRPM(0, 0);
                return;
            }

            /* Avoid loop */
            if (e.NewObject is TorquePerRPM) return;

            /* Create a new engine torque value */
            e.NewObject = new TorquePerRPM(0, 0);
        }

        private void engineTorqueBindingSource_CurrentChanged(object sender, EventArgs e)
        {

        }

        private void breakableDriveshaftsBindingSource_CurrentChanged(object sender, EventArgs e)
        {
            tbBreakableDriveshaft.Text = breakableDriveshaftsBindingSource.Current.ToStringOrEmpty();
        }

        private void waterDamageGroupsBindingSource_CurrentChanged(object sender, EventArgs e)
        {
            tbWaterDamageGroup.Text = waterDamageGroupsBindingSource.Current.ToStringOrEmpty();
        }

        private void fuelTankBeamsBindingSource_CurrentChanged(object sender, EventArgs e)
        {
            tbFuelTankBeam.Text = fuelTankBeamsBindingSource.Current.ToStringOrEmpty();
        }

        #endregion

        #region Data grid views

        private void gridGears_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            /* Clicks on headers */
            if (e.ColumnIndex < 0 || e.RowIndex < 0) return;

            /* Get column & row & cell */
            var col = gridGears.Columns[e.ColumnIndex];
            var row = gridGears.Rows[e.RowIndex];

            /* Validate new row */
            if (row.IsNewRow && col.Name.Equals("columnDeleteGear"))
            {
                gearsBindingSource.EndEdit();
                gridGears.NotifyCurrentCellDirty(true);
                gridGears.EndEdit();
                gridGears.NotifyCurrentCellDirty(false);
            }

            /* Delete row */
            else if (col.Name.Equals("columnDeleteGear"))
            {
                VehiclePart.Engine.Gears.RemoveAt(e.RowIndex);
                gearsBindingSource.ResetBindings(false);
                gridGears.Refresh();
            }
        }

        private void gridTorque_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            /* Clicks on headers */
            if (e.ColumnIndex < 0 || e.RowIndex < 0) return;

            /* Get column & row & cell */
            var col = gridTorque.Columns[e.ColumnIndex];
            var row = gridTorque.Rows[e.RowIndex];

            /* Validate new row */
            if (row.IsNewRow && col.Name.Equals("columnDeleteTorque"))
            {
                engineTorqueBindingSource.EndEdit();
                gridTorque.NotifyCurrentCellDirty(true);
                gridTorque.EndEdit();
                gridTorque.NotifyCurrentCellDirty(false);
            }

            /* Delete row */
            else if (col.Name.Equals("columnDeleteTorque"))
            {
                gridTorque.Rows.RemoveAt(e.RowIndex);
            }
        }

        #endregion

        #region Group lists buttons

        private void xbAddBreakableDriveshaft_Click(object sender, EventArgs e)
        {
            /* No text entered */
            if (string.IsNullOrEmpty(tbBreakableDriveshaft.Text))
            {
                MessageBox.Show(this, @"Please enter the name of the breakable driveshaft.", @"Empty value",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            /* Item already exists */
            if (listBreakableDriveshafts.Items.OfType<string>()
                    .Any(bd => bd.ToUpperInvariant().Equals(tbBreakableDriveshaft.Text.ToUpperInvariant())))
            {
                MessageBox.Show(this, @"An item with the same name has already been added.", @"Duplicate found",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            /* Add new item to the list */
            breakableDriveshaftsBindingSource.Add(tbBreakableDriveshaft.Text);
        }

        private void xbRemoveBreakableDriveshaft_Click(object sender, EventArgs e)
        {
            /* Empty text */
            if (string.IsNullOrEmpty(tbBreakableDriveshaft.Text))
            {
                MessageBox.Show(this, @"Please select an item or type in the name of the item to remove.",
                    @"No selection", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            /* Item not found */
            if (!listBreakableDriveshafts.Items.OfType<string>()
                .Any(bd => bd.Equals(tbBreakableDriveshaft.Text)))
            {
                MessageBox.Show(this, @"No item was found for the specified name.", @"Item not found",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            /* Remove item */
            breakableDriveshaftsBindingSource.Remove(tbBreakableDriveshaft.Text);
        }

        private void xbAddWaterDamageGroup_Click(object sender, EventArgs e)
        {
            /* No text entered */
            if (string.IsNullOrEmpty(tbWaterDamageGroup.Text))
            {
                MessageBox.Show(this, @"Please enter the name of the water damage group.", @"Empty value",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            /* Item already exists */
            if (listWaterDamageGroups.Items.OfType<string>()
                    .Any(wdg => wdg.ToUpperInvariant().Equals(tbWaterDamageGroup.Text.ToUpperInvariant())))
            {
                MessageBox.Show(this, @"An item with the same name has already been added.", @"Duplicate found",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            /* Add new item to the list */
            waterDamageGroupsBindingSource.Add(tbWaterDamageGroup.Text);
        }

        private void xbRemoveWaterDamageGroup_Click(object sender, EventArgs e)
        {
            /* Empty text */
            if (string.IsNullOrEmpty(tbWaterDamageGroup.Text))
            {
                MessageBox.Show(this, @"Please select an item or type in the name of the item to remove.",
                    @"No selection", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            /* Item not found */
            if (!listWaterDamageGroups.Items.OfType<string>()
                .Any(bd => bd.Equals(tbWaterDamageGroup.Text)))
            {
                MessageBox.Show(this, @"No item was found for the specified name.", @"Item not found",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            /* Remove item */
            waterDamageGroupsBindingSource.Remove(tbWaterDamageGroup.Text);
        }

        private void xbAddFuelTankBeam_Click(object sender, EventArgs e)
        {
            /* No text entered */
            if (string.IsNullOrEmpty(tbFuelTankBeam.Text))
            {
                MessageBox.Show(this, @"Please enter the name of a fuel tank beam.", @"Empty value",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            /* Item already exists */
            if (listFuelTankBeams.Items.OfType<string>()
                    .Any(ftb => ftb.ToUpperInvariant().Equals(tbFuelTankBeam.Text.ToUpperInvariant())))
            {
                MessageBox.Show(this, @"An item with the same name has already been added.", @"Duplicate found",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            /* Add new item to the list */
            fuelTankBeamsBindingSource.Add(tbFuelTankBeam.Text);
        }

        private void xbRemoveFuelTankBeam_Click(object sender, EventArgs e)
        {
            /* Empty text */
            if (string.IsNullOrEmpty(tbFuelTankBeam.Text))
            {
                MessageBox.Show(this, @"Please select an item or type in the name of the item to remove.",
                    @"No selection", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            /* Item not found */
            if (!listFuelTankBeams.Items.OfType<string>()
                .Any(bd => bd.Equals(tbFuelTankBeam.Text)))
            {
                MessageBox.Show(this, @"No item was found for the specified name.", @"Item not found",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            /* Remove item */
            fuelTankBeamsBindingSource.Remove(tbFuelTankBeam.Text);
        }

        #endregion

        #endregion

        #region Methods

        public override string ToString()
        {
            return "Engine";
        }

        private void BindEngine()
        {
            if (VehiclePart != null)
                engineBindingSource.DataSource = VehiclePart.Engine;

            BindGears();
            BindGroups();
        }

        private void BindGears()
        {
            gearsBindingSource.DataSource = null;

            if (VehiclePart != null)
                gearsBindingSource.DataSource = VehiclePart.Engine.Gears;
        }

        private void BindGroups()
        {
            breakableDriveshaftsBindingSource.ResetBindings(false);
            waterDamageGroupsBindingSource.ResetBindings(false);
            fuelTankBeamsBindingSource.ResetBindings(false);
        }

        protected override void OnVehiclePartChanged()
        {
            BindEngine();
            base.OnVehiclePartChanged();
        }

        #endregion
    }
}
